/*------------------------------------------------------------------------/
/  SAMG53 RTC control module
/-------------------------------------------------------------------------/
/
/  Copyright (C) 2013, ChaN, all right reserved.
/
/ * This software is a free software and there is NO WARRANTY.
/ * No restriction on use. You can use, modify and redistribute it for
/   personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
/ * Redistributions of source code must retain the above copyright notice.
/
/-------------------------------------------------------------------------*/

#include "rtc.h"

static uint32_t Bcd2Int();


long BCDtoInt(uint32_t bcd_val )
{
	int unit , dec ;
	dec = bcd_val >> 8;
	unit = bcd_val & 0xF;
	return (10*dec) + unit;
}




/*------------------------------------------*/
/* Initialize RTC                           */
/*------------------------------------------*/

int rtc_initialize (void)	/* 1:RTC is available, 0:RTC is not available */
{
	/* Disable RTC write protection */
	PMC->PMC_WPMR = (PMC_WPMR_WPKEY_PASSWD<<PMC_WPMR_WPKEY_Pos);
	// Enable RTC peripheral clock
	PMC->PMC_PCER0 |= ID_RTC;
	return 1;
}




/*------------------------------------------*/
/* Get time in calendar form                */
/*------------------------------------------*/

int rtc_gettime (RTCTIME* rtc)
{
	rtc->sec = BCDtoInt((RTC->RTC_TIMR & RTC_TIMR_SEC_Msk)>>RTC_TIMR_SEC_Pos) ;
	rtc->min = BCDtoInt((RTC->RTC_TIMR & RTC_TIMR_MIN_Msk)>>RTC_TIMR_MIN_Pos) ;
	rtc->hour = BCDtoInt((RTC->RTC_TIMR & RTC_TIMR_HOUR_Msk)>>RTC_TIMR_HOUR_Pos);
	rtc->wday = BCDtoInt((RTC->RTC_CALR & RTC_CALR_DAY_Msk)>>RTC_CALR_DAY_Pos);
	rtc->year = 100 * BCDtoInt((RTC->RTC_CALALR & RTC_CALR_CENT_Msk)>>RTC_CALR_CENT_Pos) + BCDtoInt((RTC->RTC_CALALR & RTC_CALR_YEAR_Msk)>>RTC_CALR_YEAR_Pos);
	rtc->month = BCDtoInt((RTC->RTC_CALALR & RTC_CALR_MONTH_Msk)>>RTC_CALR_MONTH_Pos);
	rtc->mday = BCDtoInt((RTC->RTC_CALALR & RTC_CALR_DAY_Msk)>>RTC_CALR_DATE_Pos);
	return 1;
}



/*------------------------------------------*/
/* Set time in calendar form                */
/*------------------------------------------*/

int rtc_settime (const RTCTIME* rtc)
{
	// Check stop possible ongoing RTC configuration request
	if(RTC->RTC_CR & (RTC_CR_UPDCAL|RTC_CR_UPDTIM))
		RTC->RTC_CR &= ~(RTC_CR_UPDCAL|RTC_CR_UPDTIM);			
	// Configure/Update RTC (see flowchart from G53 data sheet)
	// 1 - request Configuration
	RTC->RTC_CR |= (RTC_CR_UPDCAL|RTC_CR_UPDTIM);
	// 2 - Wait for ack
	while (!(RTC->RTC_SR & RTC_SR_ACKUPD));
	// 3 - Clear ACK flag
	RTC->RTC_SCCR |= RTC_SCCR_ACKCLR;
	// 4 - Set TIME value
	RTC->RTC_TIMR = ((rtc->sec << RTC_TIMR_SEC_Pos)|(rtc->min << RTC_TIMR_MIN_Pos)|(rtc->hour << RTC_TIMR_HOUR_Pos));
	// 5 - Set CALENDAR value
	RTC->RTC_CALR = ((rtc->wday << RTC_CALR_DAY_Pos)|(rtc->year << RTC_CALR_YEAR_Pos)|(rtc->month << RTC_CALR_MONTH_Pos)|(rtc->mday << RTC_CALR_DATE_Pos));
	// Stop Configuration
	RTC->RTC_CR &= ~(RTC_CR_UPDCAL|RTC_CR_UPDTIM);
	return 1;	
}


